package org.madmatrix.galarm;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.madmatrix.glib.log.ILogger;
import org.madmatrix.glib.log.LoggerFactory;
import org.madmatrix.glib.util.DateUtil;
import org.madmatrix.glib.util.FileUtil;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class GAlarmManager {

	private static ILogger logger = LoggerFactory.getLogger(GAlarmManager.class);
	private static Gson gson = new Gson();

	/**
	 * 加载所有处在活动状态的闹钟
	 * 
	 * @param context
	 * @return
	 */
	public static List<Alarm> loadAllActiveAlarms(Context context) {
		List<Alarm> alarmList = loadAllAlarms(context);
		List<Alarm> activeAlarmList = new ArrayList<Alarm>();
		for (Alarm alarm : alarmList) {
			if (alarm.isEnabled) {
				activeAlarmList.add(alarm);
			}
		}

		return activeAlarmList;
	}

	/**
	 * 从本地文件中加载所有闹钟
	 * 
	 * @param context
	 * @return
	 */
	public static List<Alarm> loadAllAlarms(Context context) {
		List<Alarm> alarmList = new ArrayList<Alarm>();
		String alarmConf = FileUtil.loadString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM);
		if (!TextUtils.isEmpty(alarmConf)) {
			alarmList = gson.fromJson(alarmConf, new TypeToken<List<Alarm>>() {
			}.getType());
		}

		return alarmList;
	}

	/**
	 * 获取一个未被使用过的id
	 * 
	 * @param context
	 * @return
	 */
	public static int generateAlarmId(Context context) {
		int currentAlarmId = FileUtil.loadInt(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM_GEN_ID, 0) + 1;
		FileUtil.saveInt(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM_GEN_ID, currentAlarmId);
		return currentAlarmId;
	}

	/**
	 * 初始化闹钟，计算触发时间
	 * 
	 * @param alarm
	 */
	public static void initAlarm(Alarm alarm) {
		alarm.triggerTimeQueue.clear();

		Calendar today = Calendar.getInstance();
		Calendar setDay = Calendar.getInstance();
		if (alarm.isRepeat) {
			// 1. 判断所有重复时间是否过期，只需要判断最后一天触发时间是否过期即可
			// 取出重复天中最后一天
			Weekday lastDay = alarm.weekdays.get(alarm.weekdays.size() - 1);
			setDay.set(Calendar.DAY_OF_WEEK, lastDay.getValue());

			// 设置时、分、秒
			setDay.set(Calendar.HOUR_OF_DAY, alarm.triggerTimeHour);
			setDay.set(Calendar.MINUTE, alarm.triggerTimeMinute);
			// 触发时间去掉秒，因为设置到期时间的时候就没有选择秒
			setDay.set(Calendar.SECOND, 0); 

			// 如果最后一个重复时间在本周内已经过期，则将所有的重复时间向后推迟7天
			if (today.after(setDay)) {
				setDay.add(Calendar.DAY_OF_MONTH, 7);
			}

			// 2. 将剩余的重复日转化为触发时间放入队列
			StringBuilder logsb = new StringBuilder(64);
			for (Weekday weekday : alarm.weekdays) {
				setDay.set(Calendar.DAY_OF_WEEK, weekday.getValue());
				if (today.before(setDay)) {
					alarm.triggerTimeQueue.offer(setDay.getTimeInMillis());
					logsb.append(DateUtil.formatDateTime(setDay.getTimeInMillis())).append(", ");
				}
			}

			// log out
			logger.d("alarm inited, triggerTimeQueue=" + logsb);
		} else {
			setDay.set(Calendar.HOUR_OF_DAY, alarm.triggerTimeHour);
			setDay.set(Calendar.MINUTE, alarm.triggerTimeMinute);
			setDay.set(Calendar.SECOND, 0);
			
			// 如果时间已经过期，则将触发日向后推一天
			if (today.after(setDay)) {
				setDay.add(Calendar.DAY_OF_MONTH, 1);
			}
			alarm.triggerTimeQueue.offer(setDay.getTimeInMillis());
		}
	}

	/**
	 * 默认用触发队列中处于对头的时间戳重置当前任务。如果resetNext为true，则对头时间出队，使用下一个时间重置当前任务
	 * 
	 * 注意：该方法只能重置处于enabled状态的闹钟
	 * 
	 * @param context
	 * @param alarm
	 * @param resetNext 是否使用下一个时间戳重置当前任务
	 */
	public static void resetAlarm(Context context, Alarm alarm, boolean resetNext) {
		if (!alarm.isEnabled) {
			logger.e("[resetAlarm]the alarm should be enabled");
			return;
		}
		
		if (alarm.triggerTimeQueue.isEmpty()) {
			initAlarm(alarm);
		}
		
		if (resetNext) {
			alarm.triggerTimeQueue.poll();
			
			if (alarm.triggerTimeQueue.isEmpty()) {
				initAlarm(alarm);
			}
		}

		AlarmManager manager = (AlarmManager) context.getSystemService(Service.ALARM_SERVICE);
		Intent intent = new Intent(context, AlarmExpireActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.putExtra("alarm", gson.toJson(alarm));
		PendingIntent pi = PendingIntent.getActivity(context, alarm.id, intent, PendingIntent.FLAG_CANCEL_CURRENT);
		manager.set(AlarmManager.RTC_WAKEUP, alarm.triggerTimeQueue.peek(), pi);
		logger.i("restart alarm successfully, alarm id=" + alarm.id + ", time=" + getAlarmHint(alarm));
	}

	/**
	 * 启用/禁用alarm。启用alarm后会重新计算触发时间；禁用alarm后则会清空所有的触发时间
	 * 
	 * @param context
	 * @param alarm
	 * @param isEnable
	 * @return
	 */
	public static boolean enableAlarm(Context context, Alarm alarm, boolean isEnable) {
		alarm.isEnabled = isEnable;
		AlarmManager manager = (AlarmManager) context.getSystemService(Service.ALARM_SERVICE);
		Intent intent = new Intent(context, AlarmExpireActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

		if (isEnable) {
			initAlarm(alarm);
			intent.putExtra("alarm", gson.toJson(alarm));
			PendingIntent pi = PendingIntent.getActivity(context, alarm.id, intent, PendingIntent.FLAG_CANCEL_CURRENT);
			manager.set(AlarmManager.RTC_WAKEUP, alarm.triggerTimeQueue.peek(), pi);
			logger.i("reset alarm successfully, alarm id=" + alarm.id + ", time=" + getAlarmHint(alarm));
		} else {
			alarm.triggerTimeQueue.clear();
			PendingIntent pi = PendingIntent.getActivity(context, alarm.id, intent, PendingIntent.FLAG_CANCEL_CURRENT);
			manager.cancel(pi);
			logger.i("alarm has been canceled, alarm id=" + alarm.id);
		}

		saveAlarm(context, alarm);

		return true;
	}

	/**
	 * 获取alarm
	 * 
	 * @param context
	 * @param alarmId
	 * @return
	 */
	public static Alarm getAlarm(Context context, int alarmId) {
		String alarmsConf = FileUtil.loadString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM);
		List<Alarm> alarmList = null;
		if (TextUtils.isEmpty(alarmsConf)) {
			return null;
		} else {
			alarmList = gson.fromJson(alarmsConf, new TypeToken<List<Alarm>>() {
			}.getType());
		}

		for (Alarm alarm : alarmList) {
			if (alarm.id == alarmId) {
				return alarm;
			}
		}
		
		return null;
	}

	/**
	 * 添加一个alarm
	 * 
	 * @param context
	 * @param alarm
	 * @return
	 */
	public static boolean addAlarm(Context context, Alarm alarm) {
		return enableAlarm(context, alarm, true);
	}

	/**
	 * 修改alarm
	 * 
	 * @param context
	 * @param alarm
	 * @return
	 */
	public static boolean editAlarm(Context context, Alarm alarm) {
		return enableAlarm(context, alarm, alarm.isEnabled);
	}

	/**
	 * 删除一个alarm，删除之前先取消该alarm
	 * 
	 * @param context
	 * @param id
	 * @return 没找到id指定的闹钟则返回false
	 */
	public static boolean deleteAlarm(Context context, long id) {
		String alarmsConf = FileUtil.loadString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM);
		List<Alarm> alarmList = null;
		if (TextUtils.isEmpty(alarmsConf)) {
			return false;
		} else {
			alarmList = gson.fromJson(alarmsConf, new TypeToken<List<Alarm>>() {
			}.getType());
		}

		int i = 0;
		for (; i < alarmList.size(); ++i) {
			if (id == alarmList.get(i).id) {
				break;
			}
		}

		if (i == alarmList.size()) {
			return false;
		} else {
			Alarm alarm = alarmList.remove(i);
			enableAlarm(context, alarm, false);
		}

		FileUtil.saveString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM, gson.toJson(alarmList));

		return true;
	}

	/**
	 * 保存alarm的配置到本地
	 * 
	 * @param context
	 * @param alarm
	 * @return
	 */
	public static boolean saveAlarm(Context context, Alarm alarm) {
		String alarmsConf = FileUtil.loadString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM);
		List<Alarm> alarmList = null;
		if (TextUtils.isEmpty(alarmsConf)) {
			alarmList = new ArrayList<Alarm>();
		} else {
			alarmList = gson.fromJson(alarmsConf, new TypeToken<List<Alarm>>() {
			}.getType());
		}

		int i = 0;
		for (; i < alarmList.size(); ++i) {
			if (alarm.id == alarmList.get(i).id) {
				break;
			}
		}

		if (i == alarmList.size()) {
			alarmList.add(alarm);
		} else {
			alarmList.set(i, alarm);
		}

		FileUtil.saveString(context, Constants.APP_NAME, Constants.CONF_KEY_ALARM, gson.toJson(alarmList));

		return true;
	}
	
	/**
	 * 获取闹钟会在多久后响起的提示
	 * 
	 * @param alarm
	 * @return
	 */
	public static String getAlarmHint(Alarm alarm) {
		if (alarm.triggerTimeQueue.isEmpty()) {
			return "";
		}
		
		long triggerDateTime = alarm.triggerTimeQueue.peek();
		long diffMills = triggerDateTime - System.currentTimeMillis();

		logger.d("[getAlarmHint]triggerDateTime=" + DateUtil.formatDateTime(triggerDateTime));

		String hint = "闹钟会在";
		long diffDay = diffMills / 1000 / 3600 / 24;
		if (diffDay > 0) {
			hint += diffDay + "天";
		}

		long diffHour = (diffMills - diffDay * 24 * 3600 * 1000) / 1000 / 60 / 60;
		if (diffHour > 0) {
			hint += diffHour + "小时";
		}

		// 向上取整，不足1分钟按1分钟算
		// 由于闹钟在设置的时候是按整点设置的（即去掉秒），因此如果直接设置成当前时间，那一定会被推迟到明天的此时响铃
		double diffMinute = Math.ceil((double) (diffMills - diffDay * 24 * 3600 * 1000 - diffHour * 3600 * 1000) / 1000 / 60);
		if (diffMinute < 0) {
			diffMinute = 0;
		}
		hint += (int) diffMinute + "分钟";
		hint += "后响起";

		return hint;
	}

	/**
	 * 获取下一次触发的时间(HH:mm)，不含日期，和秒
	 * 
	 * @param alarm
	 * @return
	 */
	public static String getTriggerTime(Alarm alarm) {
		return String.format("%02d:%02d", alarm.triggerTimeHour, alarm.triggerTimeMinute);
	}

	/**
	 * 获取重复日描述，描述可以枚举为： 每天 工作日 周末 （自定义时间）形如：周一、周三、周五
	 * 
	 * @param alarm
	 * @return
	 */
	public static String getRepeatDaysDesc(Alarm alarm) {
		String desc = "";
		if (alarm.isRepeat) {
			desc = "";
			List<Weekday> weekdays = alarm.weekdays;
			if (!weekdays.isEmpty()) {
				if (weekdays.size() == 7) {
					desc = "每天";
				} else if (weekdays.size() == 5 && !weekdays.contains(Weekday.SUNDAY) && !weekdays.contains(Weekday.SATURDAY)) {
					desc = "工作日";
				} else if (weekdays.size() == 2 && weekdays.contains(Weekday.SUNDAY) && weekdays.contains(Weekday.SATURDAY)) {
					desc = "周末";
				} else {
					for (Weekday weekday : weekdays) {
						switch (weekday) {
						case SUNDAY:
							desc += "周日、";

							break;
						case MONDAY:
							desc += "周一、";

							break;
						case TUESDAY:
							desc += "周二、";

							break;
						case WEDNESDAY:
							desc += "周三、";

							break;
						case THURSDAY:
							desc += "周四、";

							break;
						case FRIDAY:
							desc += "周五、";

							break;
						case SATURDAY:
							desc += "周六、";

							break;
						}
					}

					desc = desc.substring(0, desc.length() - 1);
				}
			}
		}

		return desc;
	}
}
